﻿using Compass.Wasm.Shared.Wms;
using Compass.Wasm.Shared;
using AutoMapper;
using Compass.WmsService.Domain;
using Compass.WmsService.Infrastructure;
using Compass.WmsService.Domain.Entities;

namespace Compass.Wasm.Server.Services.Wms;
public interface ICargoService : IBaseService<CargoDto>
{
    Task<ApiResponse<CargoDto>> GetSingleByMtlNumberAsync(string mtlNumber);
    Task<ApiResponse<IEnumerable<CargoDto>>> GetAllByAreaAsync(Warehouse_e warehouse, Area_e area, string ranks);
    Task<ApiResponse<CargoDto>> GetSingleByLocationAsync(string location);

    //查询时需要带上库存信息
    Task<ApiResponse<IEnumerable<CargoDto>>> GetTop5ByKeywordWithInventoryAsync(string? keyword);
    Task<ApiResponse<CargoDto>> GetSingleWithInventoryAsync(Guid id);
    Task<ApiResponse<IEnumerable<CargoDto>>> GetAllWithInventoryAsync();
    Task<ApiResponse<IEnumerable<CargoDto>>> GetAllByAreaWithInventoryAsync(Warehouse_e warehouse, Area_e area, string ranks);

    //MAUI


    Task<ApiResponse<IEnumerable<CargoDto>>> GetMauiAllWithInventoryAsync(int skip, int take, string? search);
    Task<ApiResponse<IEnumerable<CargoDto>>> GetMauiAllByAreaWithInventoryAsync(Warehouse_e warehouse, Area_e area, string ranks, string? search);


}
public class CargoService : ICargoService
{
    #region ctor
    private readonly WmsDbContext _dbContext;
    private readonly IWmsRepository _repository;
    private readonly IMapper _mapper;
    public CargoService(WmsDbContext dbContext, IWmsRepository repository, IMapper mapper)
    {
        _dbContext = dbContext;
        _repository = repository;
        _mapper = mapper;
    }
    #endregion
    
    #region 基本增删改查
    public async Task<ApiResponse<IEnumerable<CargoDto>>> GetAllAsync()
    {
        try
        {
            var models = await _repository.GetCargoesAsync();
            //按照料号排序
            var dtos = await _mapper.ProjectTo<CargoDto>(models).OrderBy(x => x.MtlNumber).ToListAsync();
            return new ApiResponse<IEnumerable<CargoDto>> { Status = true, Result = dtos };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<CargoDto>> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<CargoDto>> GetSingleAsync(Guid id)
    {
        try
        {
            var model = await _repository.GetCargoByIdAsync(id);
            if (model == null) return new ApiResponse<CargoDto> { Status = false, Message = "查询数据失败" };
            var dto = _mapper.Map<CargoDto>(model);
            return new ApiResponse<CargoDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<CargoDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<CargoDto>> AddAsync(CargoDto dto)
    {
        try
        {
            var model = new Cargo(Guid.NewGuid(), dto.MtlNumber.ToUpper(), dto.Description, dto.EnDescription, dto.Unit, dto.Sbu, dto.Group, dto.Consumable, dto.Inspection, dto.Location, dto.SafetyStock, dto.OrderingWay, dto.LeadTime, dto.MinimalBatch, dto.Vendors, dto.AvgPrice, dto.LastPrice, dto.Remarks, dto.ImageUrl);
            await _dbContext.Cargoes.AddAsync(model);
            dto.Id = model.Id;
            return new ApiResponse<CargoDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<CargoDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<CargoDto>> UpdateAsync(Guid id, CargoDto dto)
    {
        try
        {
            var model = await _repository.GetCargoByIdAsync(id);
            if (model == null) return new ApiResponse<CargoDto> { Status = false, Message = "更新数据失败" };
            model.Update(dto);
            return new ApiResponse<CargoDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<CargoDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<CargoDto>> DeleteAsync(Guid id)
    {
        try
        {
            var model = await _repository.GetCargoByIdAsync(id);
            if (model == null) return new ApiResponse<CargoDto> { Status = false, Message = "删除数据失败" };
            model.SoftDelete();//软删除
            return new ApiResponse<CargoDto> { Status = true };
        }
        catch (Exception e)
        {
            return new ApiResponse<CargoDto> { Status = false, Message = e.Message };
        }
    }
    #endregion
    
    #region 不带库存的查询方法
    public async Task<ApiResponse<CargoDto>> GetSingleByMtlNumberAsync(string mtlNumber)
    {
        try
        {
            var model = await _repository.GetCargoByMtlNumberAsync(mtlNumber);
            if (model == null) return new ApiResponse<CargoDto> { Status = false, Message = "查询数据失败" };
            var dto = _mapper.Map<CargoDto>(model);
            return new ApiResponse<CargoDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<CargoDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<IEnumerable<CargoDto>>> GetAllByAreaAsync(Warehouse_e warehouse, Area_e area, string ranks)
    {
        try
        {
            var models = await _repository.GetCargoesByAreaAsync(warehouse, area, ranks);
            //先按照行排序，再按照库位排序
            var dtos = await _mapper.ProjectTo<CargoDto>(models).OrderBy(x => x.Location).ToListAsync();
            return new ApiResponse<IEnumerable<CargoDto>> { Status = true, Result = dtos };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<CargoDto>> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<CargoDto>> GetSingleByLocationAsync(string location)
    {
        try
        {
            var model = await _repository.GetCargoByLocationAsync(location);
            if (model == null) return new ApiResponse<CargoDto> { Status = false, Message = "查询数据失败" };
            var dto = _mapper.Map<CargoDto>(model);
            return new ApiResponse<CargoDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<CargoDto> { Status = false, Message = e.Message };
        }
    } 
    #endregion

    #region 通用方法
    private async void FillInventoryInfo(CargoDto dto)
    {
        //Inventory=LastInventory+StockIn-StockOut
        //TransitIn=Sum(FromLastTransitIn)
        //TransitOut=Sum(FromLastStockOut)
        var lastInventory =await _repository.GetInventoryLastByCargoAsync(dto.Id!.Value);
        var lastDate = new DateTime(2024, 10, 1);
        var lastQuantity = 0d;
        if (lastInventory != null)
        {
            lastDate = lastInventory.CountTime;
            lastQuantity = lastInventory.Quantity;
        }
        var fromLastStockIn =
            await _repository.GetStockInsFromLastByCargoAsync(dto.Id.Value, lastDate);
        var fromLastStockOut =
            await _repository.GetStockOutsFromLastByCargoAsync(dto.Id.Value, lastDate);

        dto.Inventory = lastQuantity + fromLastStockIn.Sum(x => x.Quantity) -
                        fromLastStockOut.Sum(x => x.Quantity);
        dto.TransitIn = fromLastStockIn.Sum(x => x.TransitQuantity);
        dto.TransitOut = fromLastStockOut.Sum(x => x.TransitQuantity);
        dto.ShortAge = (dto.Inventory + dto.TransitIn - dto.TransitOut) <= dto.SafetyStock;
        dto.InventoryValue =Math.Round(dto.Inventory * dto.LastPrice,2) ;
    }
    #endregion

    #region 查询时需要带上库存信息
    public async Task<ApiResponse<IEnumerable<CargoDto>>> GetTop5ByKeywordWithInventoryAsync(string? keyword)
    {
        try
        {
            var models = await _repository.GetTop5CargoesByKeywordAsync(keyword);
            
            var dtos = await _mapper.ProjectTo<CargoDto>(models).ToListAsync();
            dtos.ForEach(FillInventoryInfo);

            return new ApiResponse<IEnumerable<CargoDto>> { Status = true, Result = dtos.OrderByDescending(x => x.ShortAge).ThenBy(x => x.MtlNumber) };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<CargoDto>> { Status = false, Message = e.Message };
        }

    }

    public async Task<ApiResponse<CargoDto>> GetSingleWithInventoryAsync(Guid id)
    {
        try
        {
            var model = await _repository.GetCargoByIdAsync(id);
            if (model == null) return new ApiResponse<CargoDto> { Status = false, Message = "查询数据失败" };
            var dto = _mapper.Map<CargoDto>(model);
            FillInventoryInfo(dto);
            return new ApiResponse<CargoDto> { Status = true, Result = dto };
        }
        catch (Exception e)
        {
            return new ApiResponse<CargoDto> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<IEnumerable<CargoDto>>> GetAllWithInventoryAsync()
    {
        try
        {
            var models = await _repository.GetCargoesAsync();
            //按照料号排序
            var dtos = await _mapper.ProjectTo<CargoDto>(models).ToListAsync();
            dtos.ForEach(FillInventoryInfo);
            return new ApiResponse<IEnumerable<CargoDto>> { Status = true, Result = dtos.OrderByDescending(x => x.ShortAge).ThenBy(x=>x.MtlNumber) };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<CargoDto>> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<IEnumerable<CargoDto>>> GetAllByAreaWithInventoryAsync(Warehouse_e warehouse, Area_e area, string ranks)
    {
        try
        {
            var models = await _repository.GetCargoesByAreaAsync(warehouse, area, ranks);
            //先按照行排序，再按照库位排序
            var dtos = await _mapper.ProjectTo<CargoDto>(models).ToListAsync();
            dtos.ForEach(FillInventoryInfo);

            return new ApiResponse<IEnumerable<CargoDto>> { Status = true, Result = dtos.OrderByDescending(x=>x.ShortAge).ThenBy(x => x.Location) };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<CargoDto>> { Status = false, Message = e.Message };
        }
    }



    #endregion


    #region MAUI
    public async Task<ApiResponse<IEnumerable<CargoDto>>> GetMauiAllWithInventoryAsync(int skip, int take, string? search)
    {
        try
        {
            var models = await _repository.GetCargoesAsync();
            var orderModels = models.OrderBy(x => x.MtlNumber);
            //按照料号排序
            var dtos = await _mapper.ProjectTo<CargoDto>(orderModels)
                .Where(x=>string.IsNullOrEmpty(search) ||
                          x.MtlNumber.ToLower().Contains(search.ToLower())||
                          x.Description!.ToLower().Contains(search.ToLower()))
                .Skip(skip)
                .Take(take)
                .ToListAsync();
            dtos.ForEach(FillInventoryInfo);
            return new ApiResponse<IEnumerable<CargoDto>> { Status = true, Result = dtos.OrderByDescending(x => x.ShortAge).ThenBy(x => x.MtlNumber) };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<CargoDto>> { Status = false, Message = e.Message };
        }
    }

    public async Task<ApiResponse<IEnumerable<CargoDto>>> GetMauiAllByAreaWithInventoryAsync(Warehouse_e warehouse, Area_e area, string ranks, string? search)
    {
        try
        {
            var models = await _repository.GetCargoesByAreaAsync(warehouse, area, ranks);
            var orderModels = models.OrderBy(x => x.Location);
            //先按照行排序，再按照库位排序
            var dtos = await _mapper.ProjectTo<CargoDto>(orderModels)
                .Where(x => string.IsNullOrEmpty(search) ||
                            x.MtlNumber.ToLower().Contains(search.ToLower())||
                            (!string.IsNullOrEmpty(x.Description) && x.Description!.ToLower().Contains(search.ToLower())))
                .ToListAsync();
            dtos.ForEach(FillInventoryInfo);

            return new ApiResponse<IEnumerable<CargoDto>> { Status = true, Result = dtos.OrderByDescending(x => x.ShortAge).ThenBy(x => x.Location) };
        }
        catch (Exception e)
        {
            return new ApiResponse<IEnumerable<CargoDto>> { Status = false, Message = e.Message };
        }
    }
    #endregion


}